﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.IO;
using System.Diagnostics;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

namespace SmallProgramWeb
{
    /// <summary>
    /// Summary description for Service
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class Service : System.Web.Services.WebService
    {
        public const string PROGRAM_PATH = "Program";
        public const string LIBRARY_PATH = "Library";
        public const string ASSEMBLY_PATH = "Assembly";
        public const string SETTING_FILE = "Setting.config";

        [WebMethod]
        public string SaveProgram(string title, string programText, string baseId)
        {
            if (!string.IsNullOrEmpty(programText))
            {
                // TODO:
                string programFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PROGRAM_PATH);
                int programId = GetProgramID();
                string programFileName = Path.Combine(programFolder, string.Format("{0}.cs", programId));
                try
                {
                    if (!Directory.Exists(programFolder))
                    {
                        Directory.CreateDirectory(programFolder);
                    }
                    File.WriteAllText(programFileName, programText);
                    return programId.ToString();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    return "error";
                }
            }
            return "error";
        }

        private static int GetProgramID()
        {
            int programId = 0;
            try
            {
                lock (Global.ApplicationLock)
                {
                    string settingFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, SETTING_FILE);
                    if (File.Exists(settingFileName))
                    {
                        string settingFileContent = File.ReadAllText(settingFileName);
                        if (int.TryParse(settingFileContent, out programId))
                        {                            
                        }
                    }
                    programId++;
                    File.WriteAllText(settingFileName, programId.ToString());
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            return programId;
        }

        [WebMethod]
        public string LoadProgram(string id)
        {
            if (!string.IsNullOrEmpty(id))
            {
                int programId;
                if (int.TryParse(id, out programId))
                {
                    string programFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PROGRAM_PATH);
                    string programFileName = Path.Combine(programFolder, string.Format("{0}.cs", programId));
                    try
                    {
                        string programText = File.ReadAllText(programFileName);
                        return programText;
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                        return "error";
                    }
                }
            }
            return "error";
        }

        [WebMethod]
        public byte[] LoadProgramAssembly(string id)
        {
            if (!string.IsNullOrEmpty(id))
            {
                int programId;
                if (int.TryParse(id, out programId))
                {
                    string assemblyFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ASSEMBLY_PATH);
                    string assemblyFileName = Path.Combine(assemblyFolder, string.Format("{0}.dll", programId));
                    if (File.Exists(assemblyFileName))
                    {
                        return File.ReadAllBytes(assemblyFileName);
                    }
                    else
                    {
                        string code = LoadProgram(id);
                        if ((!string.IsNullOrEmpty(code)) && (code != "error"))
                        {
                            CodeDomProvider codeDomProvider = new CSharpCodeProvider();
                            CompilerParameters compilerParameters = new CompilerParameters();

                            string libraryFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LIBRARY_PATH);
                            string mscorlibLocation = Path.Combine(libraryFolder, "mscorlib.dll");
                            compilerParameters.ReferencedAssemblies.Add(mscorlibLocation);

                            libraryFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LIBRARY_PATH);
                            string libraryLocation = Path.Combine(libraryFolder, "RaisingStudio.SmallProgram.Library.Silverlight.dll");
                            compilerParameters.ReferencedAssemblies.Add(libraryLocation);

                            compilerParameters.GenerateInMemory = true;
                            compilerParameters.OutputAssembly = assemblyFileName;
                            //compilerParameters.GenerateExecutable = false;
                            compilerParameters.TreatWarningsAsErrors = false;
                            compilerParameters.WarningLevel = 4;
                            compilerParameters.CompilerOptions = " /nostdlib";

                            CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromSource(compilerParameters, code);
                            if ((compilerResults.Errors.Count == 0) && (File.Exists(assemblyFileName)))
                            {
                                return File.ReadAllBytes(assemblyFileName);
                            }
                        }
                    }
                }
            }

            return null;
        }
    }
}
